/**
 * 仪表盘 - 宇宙画报
 * 支持以下内容:
 * - 中国火箭发射记录 (默认)
 * - 人类探月形势汇总
 * - (以后有更多图)
 * 
 * flight/universe_pictorial
 * 
 * @author Zdream
 * @date 2022-12-15
 * @since Aurora 0.4.0
 */

function create(context, key) {
  switch (key) {
    // main: 让你选择画报
    case 'main': return createMain(context);
    // content: 让你选择筛选条件, 比如火箭发射记录按照啥条件
    case 'content': return createContentPromise(context);
    // cards
    case 'cards': return createCardsPromise(context);
    default: return null;
  }
}

const optYears = [];
(function _() {
  let end = new Date().getFullYear();
  for (let y = 2013; y <= end; y++) {
    optYears.push(y);
  }
})();

const ruleMetas = [
  // 这里的 support 全从下面的 themes[x].supports[x].rules[x] 中读取
  {
    ruleName: 'page',
    resetFunc: (vItem, rule) => {
      // support = { ruleName: 'page',  defaultLimit: 20, }
      // vItem = { page, pageSize }
      vItem.pageSize = rule.defaultLimit;
      vItem.page = 1;
    },
    readFunc: (vItem, rule, data) => {
      // vItem = { page, pageSize }
      vItem.pageSize = data.params.count || rule.defaultLimit;
      vItem.page = (data.params.offset == null) ? 1 : 1 + parseInt(data.params.offset / vItem.pageSize);
    },
    changeFunc: () => {},
    writeFunc: (vItem, rule, params) => {
      params.count = vItem.pageSize;
      params.offset = (vItem.page - 1) * vItem.pageSize;
    },
  }, {
    ruleName: 'yearRange',
    resetFunc: (vItem, rule) => {
      // rule = { ruleName, fromOpts, toOpts, fromKey, toKey }
      // vItem = { from, to, fromOpts, toOpts }
      vItem.from = rule.fromOpts[0];
      vItem.to = rule.toOpts[rule.toOpts.length - 1];
      vItem.fromOpts = rule.fromOpts.slice();
      vItem.toOpts = rule.toOpts.slice();
    },
    readFunc: (vItem, rule, data) => {
      vItem.from = data.params.from;
      vItem.to = data.params.to;
    },
    changeFunc: () => {},
    writeFunc: (vItem, rule, params) => {
      params.from = vItem.from;
      params.to = vItem.to;
    },
  }, {
    ruleName: 'checkbox',
    resetFunc: (vItem, rule) => {
      // rule = { ruleName, opts, names?, key, defaultCheckAll? }
      // vItem = { values: 正在选的, indeterminate: false, checkAll: true, options: 有中文名, title }
      vItem.indeterminate = false;
      vItem.checkAll = rule.defaultCheckAll == null ? true : rule.defaultCheckAll;

      if (vItem.checkAll) {
        vItem.values = rule.opts.slice();
      } else {
        vItem.values = [];
      }

      vItem.options = rule.opts.map(opt => {
        return {
          key: opt,
          name: rule.names ? rule.names[opt] : opt,
        };
      });
      vItem.title = rule.title;
    },
    readFunc: (vItem, rule, data) => {
      const valuesFromData = data.params[rule.key];
      vItem.values = valuesFromData == null ? [] : data.params[rule.key].slice();
    },
    changeFunc: (vItem, rule, paramName) => {
      // paramName = 'checkAll', or null
      if (paramName == 'checkAll') {
        if (vItem.checkAll) { // 原来是 true, 现在改为 false
          vItem.checkAll = false;
          vItem.values = [];
        } else { // 原来是 false, 现在改为 true
          vItem.checkAll = true;
          vItem.values = rule.opts.slice();
        }
        vItem.indeterminate = false;
        return;
      }

      let allLength = rule.opts.length;
      let currentLen = vItem.values.length;
      vItem.indeterminate = currentLen != 0 && allLength != currentLen;
      vItem.checkAll = currentLen == allLength;
    },
    writeFunc: (vItem, rule, params) => {
      // 如果不选任意一个, 则不发数据
      if (vItem.values.length == 0) {
        return;
      }
      params[rule.key] = vItem.values.slice();
    },
  }, {
    ruleName: 'select', // 单选
    resetFunc: (vItem, rule) => {
      // rule = { ruleName, opts, names, key }
      // vItem = { value: 正在选的, options: 有中文名, title }
      vItem.value = rule.opts[0];
      vItem.options = rule.opts.map(opt => {
        return {
          key: opt,
          name: rule.names ? rule.names[opt] : opt,
        };
      });
      vItem.title = rule.title;
    },
    readFunc: (vItem, rule, data) => {
      vItem.value = data.params[rule.key];
    },
    changeFunc: () => {},
    writeFunc: (vItem, rule, params) => {
      params[rule.key] = vItem.value;
    },
  }, {
    ruleName: 'textMatch', // 单选
    resetFunc: (vItem, rule) => {
      // rule = { ruleName, opts, names, key }
      // vItem = { value: 文本, type: 匹配类型, title }
      vItem.value = "";
      vItem.type = "contain";
      vItem.title = rule.title;
    },
    readFunc: (vItem, rule, data) => {
      vItem.type = data.params.payloadMatchType == null ? "contain" : data.params.payloadMatchType;
      vItem.value = data.params.payload == null ? "" : data.params.payload;
    },
    changeFunc: () => {},
    writeFunc: (vItem, rule, params) => {
      params.payloadMatchType = vItem.type;
      params.payload = vItem.value;
    },
  }
];

// theme 的数据的更新来源是 flightRecords/ver2023Style.json
const themes = [
  {
    format: "planetaryExploration/moon",
    supports: [
      {
        method: 'all',
        name: '显示所有',
        rules: []
      }, {
        method: 'latest',
        name: '显示最近的',
        rules: [{
          ruleName: 'page',
          defaultLimit: 20,
        }]  
      }, {
        method: 'year',
        name: '按照年份范围查询',
        rules: [{
          ruleName: 'yearRange',
          fromOpts: [1950, 1960, 1970, 1980, 1990, 2000, 2010, 2020],
          toOpts: [1959, 1969, 1979, 1989, 1999, 2009, 2019, 2029],
          fromKey: 'from',
          toKey: 'to',
        }]
      }, {
        method: 'country',
        name: '按照国家 / 地区查询',
        rules: [{
          ruleName: 'page',
          defaultLimit: 20,
        }, {
          ruleName: 'checkbox',
          opts: ['USA', 'USSR', 'RUS', 'CN', 'JP', 'EU', 'IN', 'IL', 'KR', 'UAE'],
          names: {
            'USA' : '美国',
            'USSR' : '苏联',
            'RUS' : '俄罗斯',
            'CN' : '中国',
            'JP' : '日本',
            'EU' : '欧空局',
            'IN' : '印度',
            'IL' : '以色列',
            'KR' : '南朝鲜',
            'UAE' : '阿联酋',
          },
          key: 'countries',
          title: '国家 / 地区',
        }]
      },
    ],
  }, 
  {
    format: "flightLog/cn/ver2021",
    supports: [
      {
        method: 'latest',
        name: '最近发射的',
        rules: [{
          ruleName: 'page',
          defaultLimit: 50,
        }]  
      }, {
        method: 'year',
        name: '按照年份查询',
        rules: [{
          ruleName: 'page',
          defaultLimit: 50,
        }, {
          ruleName: 'select',
          opts: optYears,
          key: 'year',
          title: '年份',
        }]  
      }, {
        method: 'conditions',
        name: '筛选规则组合查询',
        rules: [{
          ruleName: 'page',
          defaultLimit: 50,
        }, {
          ruleName: 'checkbox',
          opts: [
            'CZ-2C', 'CZ-2D', 'CZ-2FT', 'CZ-2FY',
            'CZ-3A', 'CZ-3B', 'CZ-3C',
            'CZ-4B', 'CZ-4C',
            'CZ-5', 'CZ-5B',
            'CZ-6', 'CZ-6A', 'CZ-7', 'CZ-7A', 'CZ-8',
            'CZ-11',
            'KZ-1', 'KZ-1A', 'KZ-11',
            'SD-1', 'SD-3',
            'SQX-1', 'CERES-1', 'ZK-1',
          ],
          key: 'vehicles',
          title: '运载火箭',
          defaultCheckAll: false,
        }, {
          ruleName: 'checkbox',
          opts: [
            'FTO',
            'LEO', 'LEO/CSS',
            'SSO', 'LEO/P',
            'MTO', 'MEO', 'EEO',
            'GTO', 'SSTO', 'GEO',
            'TLI', 'HCO',
          ],
          key: 'orbits',
          title: '发射轨道',
          defaultCheckAll: false,
        }, {
          ruleName: 'checkbox',
          opts: [
            '酒泉', '太原', '西昌', '文昌', '黄海',
          ],
          key: 'sites',
          title: '发射地点',
          defaultCheckAll: false,
        }, /*{
          key: 'important',
        },*/ {
          ruleName: 'checkbox',
          opts: [
            '神舟', 'CLEP', '天舟', 'PEC', 'CMS',
          ],
          names: {
            '神舟' : '中国载人工程 - 神舟',
            '天舟' : '中国载人工程 - 天舟',
            'CLEP' : '中国探月工程',
            'PEC' : '中国行星探测工程',
            'CMS' : '中国空间站',
          },
          key: 'tags',
          title: '特殊标签',
          defaultCheckAll: false,
        }]  
      }
    ],
  }, 
  {
    format: "flightLog/cn/ver2023",
    supports: [
      {
        method: 'latest',
        name: '最近发射的',
        rules: [{
          ruleName: 'page',
          defaultLimit: 50,
        }]  
      }, {
        method: 'year',
        name: '按照年份查询',
        rules: [{
          ruleName: 'page',
          defaultLimit: 50,
        }, {
          ruleName: 'select',
          opts: optYears,
          key: 'year',
          title: '年份',
        }]  
      }, {
        method: 'conditions',
        name: '筛选规则组合查询',
        rules: [{
          ruleName: 'page',
          defaultLimit: 50,
        }, {
          ruleName: 'checkbox',
          opts: [ '等待添加' ], // see data/flightRecords/ver2023Style.json
          key: 'vehicles',
          title: '运载火箭',
          defaultCheckAll: false,
        }, {
          ruleName: 'checkbox',
          opts: [ '等待添加' ], // see data/flightRecords/ver2023Style.json
          key: 'orbits',
          title: '发射轨道',
          defaultCheckAll: false,
        }, {
          ruleName: 'checkbox',
          opts: [
            '酒泉', '太原', '西昌', '文昌', '黄海',
          ],
          key: 'sites',
          title: '发射地点',
          defaultCheckAll: false,
        }, {
          ruleName: 'checkbox',
          opts: [ /** 等待添加 */ ],
          names: { },
          key: 'tags',
          title: '特殊标签',
          defaultCheckAll: false,
        }, {
          ruleName: 'textMatch',
          key: 'payload',
          title: '载荷名',
        }]  
      }
    ],
  }
];

function updateThemes(url) {
  return fetch(url)
    .then(d => d.json())
    .then(d => {
      const theme = themes.find(t => t.format === "flightLog/cn/ver2023");
      if (theme == null) { return; }

      const cGroup = theme.supports.find(t => t.method === "conditions");
      if (cGroup == null) { return; }

      /** @type {{key:string,opts:string[]}[]} */
      const rules = cGroup.rules;
      rules.find(r => r.key === 'vehicles').opts = d.vehicles.map(v => v.name);
      rules.find(r => r.key === 'orbits').opts = d.orbits.map(v => v.name);

      let rule = rules.find(r => r.key === 'tags');
      if (rule) {
        rule.opts = d.tags.map(v => v.name);
        rule.names = {};
        d.tags.forEach(v => rule.names[v.name] = v.desc);
      }
    });
}

// 所有的 rule 必须有 key.
themes.forEach(theme => theme.supports.forEach(s => s.rules.forEach(r => {
  if (r.key == null) {
    r.key = r.ruleName;
  }
})));


function createMain(context) {
  const optFormats = themes.map(t => t.format);

  return {
    template : context.template,
    data : function () {
      return {
        dirty : false,
        status : null,

        // 要传的值
        format : '',

        // 用于 html 的选项
        optFormats,
      }
    },
    props : {
      sid : String,
    },
    methods : {
      onScreenUpdated : function () {
        this.status = context.getStatus(this.sid);
        if (this.status == null || this.status.data == null || this.dirty) {
          return;
        }
        const data = this.status.data;
        if (this.dirty == false) {
          this.format = data.format;
        }
      },
      onFormatChange : function(v) {
        this.format = v;
        this.dirty = true;
      },
      // 事件驱动
      btnSubmit : function () {
        this.dirty = false;
        context.sendCommand(this.sid, 'format', {
          format : this.format
        });
      },
      btnRefresh : function () {
        this.dirty = false;
        this.onScreenUpdated();
      },
    },
    mounted : function () {
      this.onScreenUpdated(); // 更新 status
      context.getBus().$on(context.events.KEY_SCREEN_REFRESH, this.onScreenUpdated);
      context.getBus().$on(context.events.KEY_SCREEN_CREATED, this.onScreenUpdated);
      context.getBus().$on(context.events.KEY_SCREEN_UPDATED, this.onScreenUpdated);
    },
    destroyed : function () {
      context.getBus().$off(context.events.KEY_SCREEN_REFRESH, this.onScreenUpdated);
      context.getBus().$off(context.events.KEY_SCREEN_CREATED, this.onScreenUpdated);
      context.getBus().$off(context.events.KEY_SCREEN_UPDATED, this.onScreenUpdated);
    }
  };
}


function createContentPromise(context) {
  return context.fetchHtmlScript('monitor/universe_pictorial_content.html').then(html => {
    return createContent(context, html);
  });
}

function createContent(context, html) {
  return {
    template : html,
    data : function () {
      const format = themes[0].format;
      const optMethods = themes[0].supports.map(s => {
        return {
          key : s.method, 
          name : s.name
        };
      });

      return {
        dirty : false,
        status : null,
        format,
        method : themes[0].supports[0].method,
        optMethods,

        // 要传的值
        values : [],
      }
    },
    props : {
      sid : String,
    },
    methods : {
      onScreenUpdated : function () {
        this.status = context.getStatus(this.sid);
        if (this.status == null || this.status.data == null || this.dirty) {
          return;
        }
        const data = this.status.data;
        this.format = data.format;
        this.method = data.method;
        const supportsOfCurrentFormat = themes.find(t => t.format == this.format).supports;
        this.optMethods = supportsOfCurrentFormat.map(s => {
          return {
            key : s.method, 
            name : s.name
          };
        });

        // 控制哪些组件显示
        const support = supportsOfCurrentFormat.find(s => s.method == this.method);
        this.values = support.rules.map(rule => {
          const ruleName = rule.ruleName;
          const meta = ruleMetas.find(meta => meta.ruleName == ruleName);
          const value = { ruleName, key : rule.key == null ? ruleName : rule.key };
          meta.resetFunc(value, rule);
          meta.readFunc(value, rule, data);
          meta.changeFunc(value, rule);
          return value;
        });
      },
      // 事件驱动
      btnSubmit : function () {
        const rules = themes.find(t => t.format == this.format).supports.find(s => s.method == this.method).rules;
        const params = {};

        this.values.forEach(vItem => {
          const meta = ruleMetas.find(m => m.ruleName == vItem.ruleName);
          const rule = rules.find(r => r.key == vItem.key);
          meta.writeFunc(vItem, rule, params);
        });

        this.dirty = false;
        context.sendCommand(this.sid, 'update', {
          method : this.method,
          params,
        });
      },
      btnRefresh : function () {
        this.dirty = false;
        this.onScreenUpdated();
      },
      onMethodChange : function (v) {
        this.method = v;
        this.dirty = true;

        const support = themes.find(t => t.format == this.format).supports.find(s => s.method == this.method);
        this.values = support.rules.map(rule => {
          const ruleName = rule.ruleName;
          const meta = ruleMetas.find(meta => meta.ruleName == ruleName);
          const value = { ruleName, key : rule.key == null ? ruleName : rule.key };
          meta.resetFunc(value, rule);
          return value;
        });
      },
      onChange : function(v, vItem, paramName) {
        // v: 就是 UI 传的数值
        // vItem: this.values[x]
        // paramName: 'page', 'pageSize'

        const ruleName = vItem.ruleName;
        const key = vItem.key;
        const rule = themes.find(t => t.format == this.format).supports
            .find(s => s.method == this.method).rules
            .find(r => r.key == key);
        ruleMetas.find(meta => meta.ruleName == ruleName).changeFunc(vItem, rule, paramName);
        this.dirty = true;
      },
    },
    mounted : function () {
      this.onScreenUpdated(); // 更新 status
      context.getBus().$on(context.events.KEY_SCREEN_REFRESH, this.onScreenUpdated);
      context.getBus().$on(context.events.KEY_SCREEN_CREATED, this.onScreenUpdated);
      context.getBus().$on(context.events.KEY_SCREEN_UPDATED, this.onScreenUpdated);

      if (this.format == "flightLog/cn/ver2023") {
        updateThemes(context.assetPath('data/flightRecords/ver2023Style.json'))
          .then(() => this.onScreenUpdated());
      }
    },
    destroyed : function () {
      context.getBus().$off(context.events.KEY_SCREEN_REFRESH, this.onScreenUpdated);
      context.getBus().$off(context.events.KEY_SCREEN_CREATED, this.onScreenUpdated);
      context.getBus().$off(context.events.KEY_SCREEN_UPDATED, this.onScreenUpdated);
    }
  };
}

function createCardsPromise(context) {
  return context.fetchHtmlScript('monitor/universe_pictorial_cards.html').then(html => {
    return createCards(context, html);
  })
}

function createCards(context, html) {
  return {
    template : html,
    data : function () {
      return {
        status : null,
        cards : [],
        cardTemplates : [
          {type: 'flights', name: '发射记录 (主体)'},
          {type: 'flightCounter', name: '发射概览'},
        ],
        support : false,
        dirty : false,
        valid : true,
      }
    },
    props : {
      sid : String,
    },
    methods : {
      onScreenUpdated : function () {
        this.status = context.getStatus(this.sid);
        if (this.status == null || this.status.data == null) {
          return;
        }
        // build text
        const data = this.status.data;
        this.support = data.format == 'flightLog/cn/ver2023';
        if (!this.support || this.dirty) {
          return;
        }
        this.cards = this.refreshCards();
      },
      btnAdd : function (index) {
        this.cards.splice(index, 0, { type: 'flightCounter', params: {} });
        this.dirty = true;
      },
      btnTypeChange : function (index, value) {
        if (this.cards[index].type == value) {
          return;
        }
        this.cards[index].type = value;
        this.cards[index].params = {};
        this.dirty = true;
      },
      btnRemove : function (index) {
        this.dirty = true;
        this.cards.splice(index, 1);
      },
      btnCommit : function () {
        this.submitCards();
      },
      btnRefresh : function () {
        this.dirty = false;
        this.cards = this.refreshCards();
        this.valid = true;
      },

      submitCards : function() {
        context.sendCommand(this.sid, 'layout', {cards : this.cards});
        this.cards = this.refreshCards();
        this.dirty = false;
      },
      refreshCards : function() {
        const data = this.status.data;
        return JSON.parse(JSON.stringify(data.cards));
      }
    },
    mounted : function () {
      this.onScreenUpdated(); // 更新 status
      context.getBus().$on(context.events.KEY_SCREEN_REFRESH, this.onScreenUpdated);
      context.getBus().$on(context.events.KEY_SCREEN_CREATED, this.onScreenUpdated);
      context.getBus().$on(context.events.KEY_SCREEN_UPDATED, this.onScreenUpdated);
    },
    destroyed : function () {
      context.getBus().$off(context.events.KEY_SCREEN_REFRESH, this.onScreenUpdated);
      context.getBus().$off(context.events.KEY_SCREEN_CREATED, this.onScreenUpdated);
      context.getBus().$off(context.events.KEY_SCREEN_UPDATED, this.onScreenUpdated);
    }
  };
}

export default {
  factory : create,
  tabs : [{
    key : 'content',
    name : '内容筛选',
    icon : 'highlight'
  }, {
    key : 'cards',
    name : '卡片与布局',
    icon : 'profile'
  }]
};
